import { NacosConfigClient, NacosNamingClient } from 'nacos';
import { formatServiceUrl, getLocalIP } from "./utils";
import chalk from 'chalk';

const logger = console;

interface RegisterOptions {
    serverList: string;
    /** 服务名称（如 'main-app'） */
    serviceName: string;
    /** 服务端口号 */
    port: number;
    /** 命名空间（用于环境隔离，默认 'public'） */
    namespace?: string;
}

export class nacosServiceManage {

    // 静态变量：缓存单例实例（key为配置唯一标识，value为实例）
    private static instanceMap: Map<string, nacosServiceManage> = new Map();

    public nacosClient!: NacosNamingClient;
    public configClient!: NacosConfigClient;
    public initOptions!: RegisterOptions;


    private constructor(option: RegisterOptions) {
        this.initOptions = option;
    }

    /**
     * 静态 create 方法：单例模式入口，同一配置只返回一个实例
     * @param option 初始化配置
     * @returns nacosServiceManage 实例（单例）
     */
    public static async create(option: RegisterOptions): Promise<nacosServiceManage> {
        const configKey = this.getConfigKey(option);

        if (this.instanceMap.has(configKey)) {
            logger.log(`[nacos-federation] 已存在 ${option.serviceName} 的Nacos实例，直接复用`);
            return this.instanceMap.get(configKey)!;
        }

        const instance = new nacosServiceManage(option);
        // await instance.initClient();
        await instance.initConfig();

        this.instanceMap.set(configKey, instance);
        return instance;
    }

    // 服务注册
    public async initClient() {
        this.nacosClient = new NacosNamingClient({
            logger,
            serverList: this.initOptions.serverList,
            namespace: this.initOptions.namespace || 'public',
        });
        await this.nacosClient.ready();
        this.reg()
    }

    /**
     * 生成配置唯一标识：基于 serverList + namespace + serviceName（确保不同配置对应不同实例）
     */
    private static getConfigKey(option: RegisterOptions): string {
        const namespace = option.namespace || 'public';
        return `${option.serverList}-${namespace}-${option.serviceName}`;
    }

    /**
     * 订阅配置变化
     * @param dataId
     * @param group
     */
    async subscribe(dataId: string, group: string = "DEFAULT_GROUP") {
        return new Promise(async (resolve, reject) => {
            this.configClient.subscribe({ dataId, group }, (content: any) => {
                resolve(content)
            });
        })
    }


    /**
     * 获取配置
     * @param dataId
     * @param group
     */
    async getConfig(dataId: string, group: string = "DEFAULT_GROUP") {
        const res = await this.configClient.getConfig(dataId, group)
        console.log()
        console.log(`${chalk.blue('[nacos-cluster-federation] 配置发现：')}\n ${chalk.green('➜')} ${chalk.green(dataId)} 的配置为: ${chalk.green(res)}`)
        return res;
    }

    /**
     * 从Nacos发现服务地址
     * @param serviceName 发现选项
     * @returns 服务地址（如 'http://192.168.1.101:1301'）
     */
    public async find(serviceName: string) {
        const instances = await this.nacosClient.getAllInstances(serviceName);
        // console.log("instances: ", instances);
        if (instances.length === 0) {
            throw new Error(`[nacos-federation] 未发现服务 ${serviceName} 的实例`);
        }
        return formatServiceUrl(instances[0].ip, instances[0].port);
    }

    /**
     * 初始化配置服务
     * @private
     */
    private async initConfig() {
        this.configClient = new NacosConfigClient({
            serverAddr: this.initOptions.serverList,
        });
    }

    /**
     * 注册服务到Nacos并返回客户端实例
     */
    private async reg() {
        const { serviceName, port } = this.initOptions;
        const ip = getLocalIP();
        // @ts-ignore
        await this.nacosClient.registerInstance(serviceName, { port, ip })
        logger.log()
        logger.log(chalk.blue("[nacos-cluster-federation] 服务注册："))
        logger.log(` ${chalk.green('➜')} ${chalk.green(serviceName)} (${formatServiceUrl(ip, port)}) 已注册到配置中心！`);
    }

    /**
     * 手动销毁实例（如服务下线时）
     */
    public async destroy() {
        const configKey = nacosServiceManage.getConfigKey(this.initOptions);
        // 注销 Nacos 命名客户端（如已初始化）
        try {
            if (this.nacosClient) {
                const { serviceName, port } = this.initOptions;
                const ip = getLocalIP();
                // @ts-ignore
                await this.nacosClient.deregisterInstance(serviceName, { ip, port });
                // @ts-ignore
                if (typeof this.nacosClient.close === 'function') {
                    // @ts-ignore
                    await this.nacosClient.close();
                }
                logger.log(`[nacos-federation] 服务 ${serviceName} 已从Nacos注销`);
            }
        } catch (e) {
            logger.warn('[nacos-federation] deregister warn:', e);
        }

        // 关闭配置客户端（如已初始化）
        try {
            if (this.configClient && typeof (this.configClient as any).close === 'function') {
                await (this.configClient as any).close();
            }
        } catch (e) {
            logger.warn('[nacos-federation] configClient close warn:', e);
        }

        // 从缓存中移除实例
        nacosServiceManage.instanceMap.delete(configKey);
    }

    /** 销毁所有实例：用于构建结束/进程退出时清理 */
    public static async destroyAll(): Promise<void> {
        const tasks: Promise<any>[] = [];
        for (const [, instance] of nacosServiceManage.instanceMap) {
            tasks.push(instance.destroy().catch(err => logger.warn('[nacos-federation] destroyAll warn:', err)));
        }
        await Promise.allSettled(tasks);
        nacosServiceManage.instanceMap.clear();
    }
}